www.gusucode.com > VC++ 酒店管理系统-源码程序 > VC++ 酒店管理系统-源码程序/code/hotel2003/FloatControls/CoolControlsManager.cpp
//Download by http://www.NewXing.com /****************************************************************** $Archive: /MfcExt/Source/CoolControlsManager.cpp $ $Workfile: CoolControlsManager.cpp $ $Author: Bogdan Ledwig $ $Date: 99-04-26 22:12 $ $Revision: 13 $ *******************************************************************/ #include "StdAfx.h" #include "CoolControlsManager.h" // If you don't want to see extra TRACE diagnostics, // modify the line below to: #define CCM_TRACE #define CCM_TRACE TRACE #define CCM_TIMER_VAL 100 // 100 ms timer period seems to be good enough... #define MAX_CLASSNAME 64 // Length of buffer for retrieving the class name //////////////////////////////////////////////////////////////////////// // CCMControl static members initialization HWND CCoolControlsManager::CCMControl::m_hWndOld = NULL; CMapPtrToPtr CCoolControlsManager::m_ctrlMap = 10; CMapPtrToPtr CCoolControlsManager::m_dlgMap = 10; BOOL CCoolControlsManager::m_bEnabled = TRUE; // Changed 02.03.1999 Mike Walter CMapWordToPtr CCoolControlsManager::m_threadMap = 10; /////////////////////////////////////////////////////////////////////// // Here is the one and only CCoolControlsManager object static CCoolControlsManager g_ctrlManager; CCoolControlsManager& GetCtrlManager() { return g_ctrlManager; } //////////////////////////////////////////////////////////////////////// // WH_CALLWNDPROC hook procedure LRESULT CALLBACK CCM_CallWndProc( int nCode, WPARAM wParam, LPARAM lParam ) { HOOKPROC hHookProc; if ( g_ctrlManager.m_threadMap.Lookup( (WORD)GetCurrentThreadId(), (void*&)hHookProc ) == FALSE ) { // TRACE( "CCoolControlsManager: No hook for this thread installed!\n" ); return 0; } if ( nCode == HC_ACTION ) { CWPSTRUCT* pwp = (CWPSTRUCT*)lParam; if ( g_ctrlManager.IsEnabled() ) { if ( g_ctrlManager.m_bDialogOnly == TRUE ) { if ( pwp->message == WM_INITDIALOG ) g_ctrlManager.Install( pwp->hwnd ); } else if ( pwp->message == WM_CREATE && g_ctrlManager.IsEnabled() ) { TCHAR szBuf[MAX_CLASSNAME]; if ( GetWindowLong( pwp->hwnd, GWL_STYLE ) & WS_CHILD ) { GetClassName( pwp->hwnd, szBuf, MAX_CLASSNAME ); if ( lstrcmp( szBuf, _T( "ScrollBar" ) ) ) // Don't add scrollbars g_ctrlManager.AddControl( pwp->hwnd ); } } } } // Changed 02.03.1999 Mike Walter return CallNextHookEx( (HHOOK)hHookProc, nCode, wParam, lParam ); } // Install a hook for the current thread only void CCoolControlsManager::InstallHook( DWORD dwThreadID, BOOL bDialogOnly ) { // ASSERT( m_hkWndProc == NULL ); m_bDialogOnly = bDialogOnly; // Changes 02.03.1999 Mike Walter HOOKPROC hNewHook; if ( m_threadMap.Lookup( (WORD)( dwThreadID == -1 ? GetCurrentThreadId() : dwThreadID ), (void*&)hNewHook ) == FALSE ) { hNewHook = (HOOKPROC)SetWindowsHookEx( WH_CALLWNDPROC, (HOOKPROC)CCM_CallWndProc, NULL, ( dwThreadID == -1 ? GetCurrentThreadId() : dwThreadID ) ); m_threadMap.SetAt( (WORD)( dwThreadID == -1 ? GetCurrentThreadId() : dwThreadID ), hNewHook ); CCM_TRACE( "CCoolControlsManager: WH_CALLWNDPROC hook installed for thread: %d\n", ( dwThreadID == -1 ? GetCurrentThreadId() : dwThreadID ) ); } else CCM_TRACE( "CCoolControlsManager: WH_CALLWNDPROC hook already installed for thread: %d!\n", ( dwThreadID == -1 ? GetCurrentThreadId() : dwThreadID ) ); } // Install a global hook for all windows in the system. // This function may be called only when is put in a DLL. void CCoolControlsManager::InstallGlobalHook( HINSTANCE hInstance, BOOL bDialogOnly ) { ASSERT( hInstance ); // hInstance must not be NULL! ASSERT( m_hkWndProc == NULL ); m_bDialogOnly = bDialogOnly; HOOKPROC hkProc = (HOOKPROC)GetProcAddress( hInstance, "CCM_CallWndProc" ); m_hkWndProc = (HOOKPROC)SetWindowsHookEx( WH_CALLWNDPROC, (HOOKPROC)hkProc, hInstance, 0 ); CCM_TRACE( _T( "CCoolControlsManager: WH_CALLWNDPROC global hook installed\n" ) ); } void CCoolControlsManager::UninstallHook( DWORD dwThreadID ) { // ASSERT( m_hkWndProc != NULL ); // Changes 02.03.1999 Mike Walter HOOKPROC hHookProc; if ( dwThreadID == -1 ) { if ( g_ctrlManager.m_threadMap.Lookup( (WORD)GetCurrentThreadId(), (void*&)hHookProc ) == FALSE ) { CCM_TRACE( "CCoolControlsManager: No hook installed for thread: %d!\n", GetCurrentThreadId() ); return; } UnhookWindowsHookEx( (HHOOK)hHookProc ); m_threadMap.RemoveKey( (WORD)GetCurrentThreadId() ); CCM_TRACE( "CCoolControlsManager: Hook uninstalled for thread: %d\n", GetCurrentThreadId() ); CCM_TRACE( "CCoolControlsManager: Thread map has %d items\n",g_ctrlManager.m_threadMap.GetCount() ); } else { if ( g_ctrlManager.m_threadMap.Lookup( (WORD)dwThreadID, (void*&)hHookProc) == FALSE ) { CCM_TRACE( "CCoolControlsManager: No hook installed for thread: %d!\n", dwThreadID ); return; } UnhookWindowsHookEx( (HHOOK)hHookProc ); m_threadMap.RemoveKey( (WORD)dwThreadID ); CCM_TRACE( "CCoolControlsManager: Hook uninstalled for thread: %d\n", dwThreadID ); CCM_TRACE( "CCoolControlsManager: Thread map has %d items\n", g_ctrlManager.m_threadMap.GetCount() ); } if ( m_uTimerID && g_ctrlManager.m_threadMap.IsEmpty() == TRUE ) KillTimer( NULL, m_uTimerID ); } ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CCoolControlsManager::CCoolControlsManager() { m_hkWndProc = NULL; m_uTimerID = 0; CCM_TRACE( _T( "CCoolControlsManager::CCoolControlsManager()\n" ) ); } CCoolControlsManager::~CCoolControlsManager() { // Changed 02.03.1999 Mike Walter POSITION pos = m_threadMap.GetStartPosition(); while ( pos ) { HOOKPROC hHook; DWORD dwThreadID = 0; m_threadMap.GetNextAssoc( pos, (WORD&)dwThreadID, (void*&)hHook ); UninstallHook( dwThreadID ); } // If we have any elements in the map (normally impossible), unsubclass they and remove pos = m_ctrlMap.GetStartPosition(); while ( pos ) { HWND hWnd; CCMControl* pCtl; m_ctrlMap.GetNextAssoc( pos, (void*&)hWnd, (void*&)pCtl ); pCtl->Unsubclass(); m_ctrlMap.RemoveKey( hWnd ); delete pCtl; } // Now do the same things for dialog map pos = m_dlgMap.GetStartPosition(); while ( pos ) { HWND hWnd; CCMDialog* pCtl; m_dlgMap.GetNextAssoc( pos, (void*&)hWnd, (void*&)pCtl ); pCtl->Unsubclass(); m_dlgMap.RemoveKey( hWnd ); delete pCtl; } CCM_TRACE( "CCoolControlsManager::~CCoolControlsManager()\n" ); } void CCoolControlsManager::Install( HWND hWnd ) { CCMControl* pCtl; if ( m_dlgMap.Lookup( hWnd, (void*&)pCtl ) ) // Already in the dialog map return; // Iterate through all child windows HWND hCtrl = GetTopWindow( hWnd ); while ( hCtrl ) { if ( GetWindowLong( hCtrl, GWL_STYLE ) & WS_CHILD ) { TCHAR szBuf[MAX_CLASSNAME]; GetClassName( hCtrl, szBuf, MAX_CLASSNAME ); if ( lstrcmpi( szBuf, _T( "#32770" ) ) ) // Never add child dialogs! AddControl( hCtrl ); } hCtrl = GetNextWindow( hCtrl, GW_HWNDNEXT ); } AddDialog( hWnd ); // Add parent window as well // Now redraw all recently inserted controls hCtrl = GetTopWindow( hWnd ); while ( hCtrl ) { if ( m_ctrlMap.Lookup( hCtrl, (void*&)pCtl ) ) pCtl->DrawBorder(); hCtrl = GetNextWindow( hCtrl, GW_HWNDNEXT ); } } void CCoolControlsManager::Uninstall( HWND hWnd ) { // Remove all window controls from the map // when the window is about to destroy CCM_TRACE( _T( "CCoolControlsManager: Uninstall, handle: %X\n" ), hWnd ); HWND hCtrl = GetTopWindow( hWnd ); while ( hCtrl ) { if ( GetWindowLong( hCtrl, GWL_STYLE ) & WS_CHILD ) RemoveControl( hCtrl ); hCtrl = GetNextWindow( hCtrl, GW_HWNDNEXT ); } } // In lpszClass you can specify class name, which will be used // instead of true class name (useful for non-standard controls // that are similar to the one of those we have supported) BOOL CCoolControlsManager::AddControl( HWND hWnd, LPCTSTR lpszClass ) { CCMControl* pCtl = NULL; // Must not be NULL or already in the map if ( hWnd == NULL || m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) ) return FALSE; TCHAR szBuf[MAX_CLASSNAME]; if ( lpszClass == NULL ) GetClassName( hWnd, szBuf, MAX_CLASSNAME ); else lstrcpy( szBuf, lpszClass ); DWORD dwStyle = GetWindowLong( hWnd, GWL_STYLE ); DWORD dwExStyle = GetWindowLong( hWnd, GWL_EXSTYLE ); if ( !lstrcmpi( szBuf, _T( "Button" ) ) ) { if ( ( dwStyle & BS_OWNERDRAW ) == BS_OWNERDRAW ) return FALSE; // Do not subclass ownerdraw buttons else if ( ( dwStyle & BS_GROUPBOX ) == BS_GROUPBOX || ( dwStyle & BS_FLAT ) == BS_FLAT ) return FALSE; // Skip all group boxes and flat buttons else if ( ( dwStyle & BS_AUTOCHECKBOX ) == BS_AUTOCHECKBOX || ( dwStyle & BS_CHECKBOX ) == BS_CHECKBOX || ( dwStyle & BS_3STATE ) == BS_3STATE ) pCtl = new CCMCheckBox; else if ( ( dwStyle & BS_AUTORADIOBUTTON ) == BS_AUTORADIOBUTTON || ( dwStyle & BS_RADIOBUTTON ) == BS_RADIOBUTTON ) pCtl = new CCMRadioButton; else pCtl = new CCMPushButton; // If none of the above then it must be a pushbutton! } else if ( !lstrcmpi( szBuf, _T( "ComboBox" ) ) ) { // Special case for simple comboboxes if ( ( dwStyle & 0x03 ) == CBS_SIMPLE ) { hWnd = GetTopWindow( hWnd ); while ( hWnd ) { AddControl( hWnd ); hWnd = GetNextWindow( hWnd, GW_HWNDNEXT ); } return FALSE; } else pCtl = new CCMComboBox; } else if ( !lstrcmpi( szBuf, _T( "Edit" ) ) ) { // Edit window in a simple combobox GetClassName( GetParent( hWnd ), szBuf, MAX_CLASSNAME ); if ( !lstrcmpi( szBuf, _T( "ComboBox" ) ) && ( GetWindowLong( GetParent( hWnd ), GWL_STYLE ) & 0x03 ) == CBS_SIMPLE ) pCtl = new CCMEditCombo; else { if ( dwExStyle & WS_EX_CLIENTEDGE ) pCtl = new CCMEdit; } #if defined _DEBUG lstrcpy( szBuf, _T( "Edit" ) ); #endif } else if ( !lstrcmpi( szBuf, _T( "ListBox" ) ) ) { if ( dwExStyle & WS_EX_CLIENTEDGE ) pCtl = new CCMControl; } else if ( !lstrcmpi( szBuf, _T( "SysListView32" ) ) ) { if ( dwExStyle & WS_EX_CLIENTEDGE ) { pCtl = new CCMControl; AddControl( GetTopWindow( hWnd ) ); // Don't forget to add the header control } } else if ( !lstrcmpi( szBuf, _T( "SHELLDLL_DefView" ) ) ) // In open/save common dialogs { AddControl( GetTopWindow( hWnd ) ); // Add child ListView control return FALSE; } else if ( !lstrcmpi( szBuf, _T( "SysTreeView32" ) ) ) { if ( dwExStyle & WS_EX_CLIENTEDGE ) pCtl = new CCMControl; } else if ( !lstrcmpi( szBuf, _T( "SysDateTimePick32" ) ) ) { if ( dwExStyle & WS_EX_CLIENTEDGE ) { pCtl = new CCMDateTime; if ( dwStyle & DTS_UPDOWN ) AddControl( GetTopWindow( hWnd ) ); // Add up-down control as well } } else if ( !lstrcmpi( szBuf, _T( "SysMonthCal32" ) ) ) pCtl = new CCMControl; else if ( !lstrcmpi( szBuf, _T( "msctls_updown32" ) ) ) pCtl = new CCMUpDown; else if ( !lstrcmpi( szBuf, _T( "ComboLBox" ) ) ) { if ( dwExStyle & WS_EX_CLIENTEDGE ) pCtl = new CCMControl; } else if ( !lstrcmpi( szBuf, _T( "ScrollBar" ) ) ) { if ( !( dwStyle & SBS_SIZEBOX ) && !( dwStyle & SBS_SIZEGRIP ) ) pCtl = new CCMScrollBar; } else if ( !lstrcmpi( szBuf, _T( "ComboBoxEx32" ) ) ) { AddControl( GetTopWindow( hWnd ) ); return FALSE; } else if ( !lstrcmpi( szBuf, _T( "msctls_hotkey32" ) ) ) { if ( dwExStyle & WS_EX_CLIENTEDGE ) pCtl = new CCMControl; } else if ( !lstrcmpi( szBuf, _T( "SysIPAddress32" ) ) ) { if ( dwExStyle & WS_EX_CLIENTEDGE ) pCtl = new CCMIPAddress; } else if ( !lstrcmpi( szBuf, _T( "msctls_trackbar32" ) ) ) pCtl = new CCMTrackbar; else if ( !lstrcmpi( szBuf, _T( "RichEdit" ) ) ) { if ( dwExStyle & WS_EX_CLIENTEDGE ) pCtl = new CCMControl; } else if ( !lstrcmpi( szBuf, _T( "RichEdit20W" ) ) ) { if ( dwExStyle & WS_EX_CLIENTEDGE ) pCtl = new CCMControl; } else if ( !lstrcmpi( szBuf, _T( "SysHeader32" ) ) ) { if ( dwStyle & HDS_BUTTONS ) pCtl = new CCMHeaderCtrl; else return FALSE; } else if ( !lstrcmpi( szBuf, _T( "ToolbarWindow32" ) ) ) { // Skip the flat toolbars if ( dwStyle & TBSTYLE_FLAT ) return FALSE; HWND hCtrl = GetTopWindow( hWnd ); // Add additional toolbar controls while ( hCtrl ) { AddControl( hCtrl ); hCtrl = GetNextWindow( hCtrl, GW_HWNDNEXT ); } pCtl = new CCMToolbar; } else if ( !lstrcmpi( szBuf, _T( "SysTabControl32" ) ) ) { pCtl = new CCMTabControl; HWND hWndTop = GetTopWindow( hWnd ); if ( hWndTop ) AddControl( hWndTop ); // Also add the up-down control (horizontal tabs only) } else // Unknown control, do not process return FALSE; if ( pCtl ) { CCM_TRACE( _T( "CCoolControlsManager::AddControl, handle: %X, type: %s\n" ), hWnd, szBuf ); // Perform window subclassing pCtl->Subclass( hWnd, CCM_ControlProc ); // Add the control to the map m_ctrlMap.SetAt( hWnd, pCtl ); if ( m_uTimerID == 0 ) // If timer is not initialized yet { m_uTimerID = SetTimer( NULL, 0, CCM_TIMER_VAL, CCM_TimerProc ); CCM_TRACE( _T( "CControlManager: Timer created\n" ) ); ASSERT( m_uTimerID ); // Failed to create the timer } return TRUE; } return FALSE; } BOOL CCoolControlsManager::RemoveControl( HWND hWnd ) { BOOL bResult = TRUE; CCMControl* pCtl; if ( m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) == FALSE ) bResult = FALSE; #if defined _DEBUG TCHAR szBuf[MAX_CLASSNAME]; GetClassName( hWnd, szBuf, MAX_CLASSNAME ); CCM_TRACE( _T( "CCoolControlsManager::RemoveControl, handle: %X, class: %s, " ), hWnd, szBuf ); CCM_TRACE( bResult ? _T( "OK\n" ) : _T( "fail\n" ) ); #endif if ( bResult == TRUE ) { // Unsubclass window and next remove it from the map pCtl->Unsubclass(); m_ctrlMap.RemoveKey( hWnd ); delete pCtl; // Destroy the object if ( m_ctrlMap.IsEmpty() ) { KillTimer( NULL, m_uTimerID ); CCM_TRACE( _T( "CCoolControlsManager: Timer killed, map is empty\n" ) ); m_uTimerID = 0; } else CCM_TRACE( _T( "CCoolControlsManager: map has %d items\n" ), m_ctrlMap.GetCount() ); } return bResult; } void CCoolControlsManager::AddDialog( HWND hWnd ) { if ( hWnd ) { CCMDialog* pCtl = new CCMDialog; pCtl->Subclass( hWnd, CCM_DialogProc ); // Perform window subclassing m_dlgMap.SetAt( hWnd, pCtl ); // Add the dialog to the map } } void CCoolControlsManager::RemoveDialog( HWND hWnd ) { CCMDialog* pCtl; if ( m_dlgMap.Lookup( hWnd, (void*&)pCtl ) == TRUE ) { // Unsubclass window and next remove it from the map pCtl->Unsubclass(); m_dlgMap.RemoveKey( hWnd ); delete pCtl; // Destroy the object } } static void CALLBACK CCM_TimerProc( HWND /*hwnd*/, UINT /*uMsg*/, UINT /*idEvent*/, DWORD /*dwTime*/ ) { g_ctrlManager.TimerProc(); } void CCoolControlsManager::TimerProc() { // Do not process when the map is empty or the capture is set if ( m_ctrlMap.IsEmpty() || GetCapture() != NULL ) return; POINT point; GetCursorPos( &point ); HWND hWnd = WindowFromPoint( point ); CCMControl* pCtl; // Lookup for a window in the map if ( m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) == FALSE ) // Not found { // If window does not exist in the map, it can be // a child of the control (e.g. edit control in ComboBox // or header control in ListView). If so, get the parent window and // carry on hWnd = GetParent( hWnd ); // Not our window, so just reset previous control and exit if ( hWnd == NULL || m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) == FALSE ) { // Not our window, so just reset previous control and exit if ( m_ctrlMap.Lookup( CCMControl::m_hWndOld, (void*&)pCtl ) == TRUE ) { pCtl->SetState( dsHover, 0 ); CCMControl::m_hWndOld = NULL; } return; } } if ( pCtl->NeedRedraw( point ) ) // Window has been found and needs to be redrawn! { // First, reset old control (if any) CCMControl* pCtlOld; if ( m_ctrlMap.Lookup( CCMControl::m_hWndOld, (void*&)pCtlOld ) == TRUE ) { pCtlOld->SetState( dsHover, 0 ); CCMControl::m_hWndOld = NULL; } // Redraw control under the cursor pCtl->SetState( 0, dsHover ); CCMControl::m_hWndOld = hWnd; } } /////////////////////////////////////////////////////////////////////// // All messages from subclassed dialogs will come here static LRESULT CALLBACK CCM_DialogProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { // Try to find dialog in the dialog map CCoolControlsManager::CCMDialog* pCtl; if ( g_ctrlManager.m_dlgMap.Lookup( hWnd, (void*&)pCtl ) == FALSE ) { // This is not our dialog, so just apply default processing return DefWindowProc( hWnd, uMsg, wParam, lParam ); } // Otherwise, let the dialog to process this message return pCtl->WindowProc( uMsg, wParam, lParam ); } /////////////////////////////////////////////////////////////////////// // All messages from subclassed controls will come here static LRESULT CALLBACK CCM_ControlProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { CCoolControlsManager::CCMControl* pCtl; // Try to find window in the control map if ( g_ctrlManager.m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) == FALSE ) { // This is not our window, so just apply default processing return DefWindowProc( hWnd, uMsg, wParam, lParam ); } // Otherwise, let the control to process this message return pCtl->WindowProc( uMsg, wParam, lParam ); } ////////////////////////////////////////////////////////////////////////////// // CCMControl and derived classes CCoolControlsManager::CCMControl::CCMControl() { m_hWnd = NULL; m_oldWndProc = NULL; m_nState = dsNormal; m_nOldState = dsNormal; } void CCoolControlsManager::CCMControl::PrepareDraw( HDC& hDC, RECT& rect ) { GetWindowRect( m_hWnd, &rect ); OffsetRect( &rect, -rect.left, -rect.top ); hDC = GetWindowDC( m_hWnd ); } void CCoolControlsManager::CCMControl::DrawBorder() { HDC hDC; RECT rect; PrepareDraw( hDC, rect ); if ( GetWindowLong( m_hWnd, GWL_EXSTYLE ) & WS_EX_CLIENTEDGE ) { RECT rc; GetWindowRect( m_hWnd, &rc ); POINT point = { 0, 0 }; ClientToScreen( m_hWnd, &point ); if ( point.x == rc.left + 3 ) InflateRect( &rect, -1, -1 ); } if ( IsFocused() == TRUE ) m_nState |= dsFocus; else m_nState &= ~dsFocus; // Single line control looks better when this style is added if ( ( rect.bottom - rect.top ) < 30 ) m_nState |= dsAlternate; else m_nState &= ~dsAlternate; if ( ( m_nOldState & dsHover && m_nState & dsHover ) || ( m_nOldState & dsFocus && m_nState & dsFocus ) ) ; // If previous state is the same as current state, do nothing else { // Perform control-specific drawing routines CCM_TRACE( _T( "CCoolControlsManager::DrawBorder, handle: %X state: %d\n" ), m_hWnd, m_nState ); DrawControl( hDC, rect ); } // Update old state m_nOldState = m_nState; ReleaseDC( WindowFromDC( hDC ), hDC ); } BOOL CCoolControlsManager::CCMControl::NeedRedraw( const POINT& /*point*/ ) { return m_hWnd != m_hWndOld ? TRUE : FALSE; } void CCoolControlsManager::CCMCore::Subclass( HWND hWnd, WNDPROC wndNewProc ) { ASSERT( hWnd ); // Do you really want to subclass a window that has a NULL handle? m_hWnd = hWnd; // Store address of the original window procedure m_oldWndProc = (WNDPROC)GetWindowLong( m_hWnd, GWL_WNDPROC ); // And set the new one SetWindowLong( m_hWnd, GWL_WNDPROC, (LONG)wndNewProc ); } void CCoolControlsManager::CCMCore::Unsubclass() { SetWindowLong( m_hWnd, GWL_WNDPROC, (LONG)m_oldWndProc ); } LRESULT CCoolControlsManager::CCMControl::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch ( uMsg ) { // Generic messages case WM_KILLFOCUS: case WM_SETFOCUS: DrawBorder(); break; case WM_PAINT: case WM_NCPAINT: case WM_ENABLE: CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); DrawBorder(); return 0; case WM_NCDESTROY: // Unsubclass window and remove it from the map CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); g_ctrlManager.RemoveControl( m_hWnd ); return 0; } return CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); } void CCoolControlsManager::CCMControl::DrawControl( HDC hDC, const RECT& rc ) { if ( m_nState & dsHoverMask ) { Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT, COLOR_3DDKSHADOW, COLOR_3DLIGHT ); } else { if ( IsWindowEnabled( m_hWnd ) == FALSE || m_nState & dsDisabled ) Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT, COLOR_3DFACE, COLOR_3DFACE ); else Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT, m_nState & dsAlternate ? COLOR_3DHIGHLIGHT : COLOR_3DLIGHT, COLOR_3DLIGHT ); } DrawScrollBars( hDC, rc ); } void CCoolControlsManager::CCMControl::DrawScrollbarThumb( HDC hDC, const RECT& rc ) { if ( m_nState & dsHoverMask ) Draw3dBorder( hDC, rc, COLOR_3DFACE, COLOR_3DDKSHADOW, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW ); else Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW, COLOR_3DFACE, COLOR_3DFACE ); } void CCoolControlsManager::CCMControl::DrawScrollBars( HDC hDC, const RECT& rect ) { const int nFrameSize = GetSystemMetrics( SM_CXEDGE ); const int nScrollSize = GetSystemMetrics( SM_CXHSCROLL ); RECT rc; DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE ); if ( dwStyle & WS_HSCROLL && dwStyle & WS_VSCROLL ) { rc.left = rect.left + nFrameSize; rc.top = rect.bottom - nFrameSize - nScrollSize; rc.right = rect.right - nFrameSize - nScrollSize; rc.bottom = rect.bottom - nFrameSize; DrawScrollBar( hDC, rc, SB_HORZ ); rc.left = rect.right - nFrameSize - nScrollSize; rc.top = rect.top + nFrameSize; rc.right = rect.right - nFrameSize; rc.bottom = rect.bottom - nFrameSize - nScrollSize; DrawScrollBar( hDC, rc, SB_VERT ); } else if ( dwStyle & WS_VSCROLL ) { rc.left = rect.right - nFrameSize - nScrollSize; rc.top = rect.top + nFrameSize; rc.right = rect.right - nFrameSize; rc.bottom = rect.bottom - nFrameSize; DrawScrollBar( hDC, rc, SB_VERT ); } else if ( dwStyle & WS_HSCROLL ) { rc.left = rect.left + nFrameSize; rc.top = rect.bottom - nFrameSize - nScrollSize; rc.right = rect.right - nFrameSize; rc.bottom = rect.bottom - nFrameSize; DrawScrollBar( hDC, rc, SB_HORZ ); } } void CCoolControlsManager::CCMControl::DrawScrollBar( HDC hDC, const RECT& rect, int nType, BOOL bScrollbarCtrl ) { int nScrollSize = GetSystemMetrics( SM_CXHSCROLL ); // The minimal thumb size depends on the system version // For Windows 98 minimal thumb size is a half of scrollbar size // and for Windows NT is always 8 pixels regardless of system metrics. // I really don't know why. int nMinThumbSize; if ( GetVersion() & 0x80000000 ) // Windows 98 code nMinThumbSize = nScrollSize / 2; else nMinThumbSize = 8; // Calculate the arrow rectangles RECT rc1 = rect, rc2 = rect; if ( nType == SB_HORZ ) { if ( ( rect.right - rect.left ) < 2 * nScrollSize ) nScrollSize = ( rect.right - rect.left ) / 2; rc1.right = rect.left + nScrollSize; rc2.left = rect.right - nScrollSize; } else // SB_VERT { if ( ( rect.bottom - rect.top ) < 2 * nScrollSize ) nScrollSize = ( rect.bottom - rect.top ) / 2; rc1.bottom = rect.top + nScrollSize; rc2.top = rect.bottom - nScrollSize; } // Draw the scrollbar arrows DrawScrollbarThumb( hDC, rc1 ); DrawScrollbarThumb( hDC, rc2 ); // Disabled scrollbar never have a thumb if ( bScrollbarCtrl == TRUE && IsWindowEnabled( m_hWnd ) == FALSE ) return; SCROLLINFO si; si.cbSize = sizeof( SCROLLINFO ); si.fMask = SIF_ALL; GetScrollInfo( m_hWnd, bScrollbarCtrl ? SB_CTL : nType, &si ); // Calculate the size and position of the thumb int nRange = si.nMax - si.nMin + 1; if ( nRange ) { int nScrollArea = ( nType == SB_VERT ? ( rect.bottom - rect.top ) : ( rect.right - rect.left ) ) - 2 * nScrollSize; int nThumbSize; if ( si.nPage == 0 ) // If nPage is not set then thumb has default size nThumbSize = GetSystemMetrics( SM_CXHTHUMB ); else nThumbSize = max( MulDiv( si.nPage ,nScrollArea, nRange ), nMinThumbSize ); if ( nThumbSize >= nScrollArea ) { nThumbSize = nScrollArea; if ( bScrollbarCtrl == FALSE ) return; } int nThumbPos; if ( UINT( nRange ) == si.nPage ) { nThumbPos = 0; nThumbSize--; } else nThumbPos = MulDiv( si.nPos - si.nMin, nScrollArea - nThumbSize, nRange - si.nPage ); if ( nType == SB_VERT ) { rc1.top += nScrollSize + nThumbPos; rc1.bottom = rc1.top + nThumbSize; } else // SB_HORZ { rc1.left += nScrollSize + nThumbPos; rc1.right = rc1.left + nThumbSize; } if ( nThumbSize <= nScrollArea ) // Don't draw the thumb when it's larger than the scroll area DrawScrollbarThumb( hDC, rc1 ); } } BOOL CCoolControlsManager::CCMControl::IsFocused() { return m_hWnd == GetFocus() ? TRUE : FALSE; } ////////////////////////////////////////////////////////////////////////////// // CCMEdit class void CCoolControlsManager::CCMEdit::DrawControl( HDC hDC, const RECT& rc ) { RECT rect = rc; // Check if edit window has an associated up-down control. // If so draw a border around both controls HWND hWnd = GetNextWindow( m_hWnd, GW_HWNDNEXT ); if ( hWnd ) { TCHAR szBuf[MAX_CLASSNAME]; // Retrieve window class name GetClassName( hWnd, szBuf, MAX_CLASSNAME ); if ( lstrcmpi( szBuf, _T( "msctls_updown32" ) ) == 0 ) // Up-down is found { DWORD dwStyle = GetWindowLong( hWnd, GWL_STYLE ); if ( ( dwStyle & UDS_ALIGNRIGHT || dwStyle & UDS_ALIGNLEFT ) && SendMessage( hWnd, UDM_GETBUDDY, 0, 0L ) == (LONG)m_hWnd ) { RECT rc; GetWindowRect( hWnd, &rc ); const int nEdge = GetSystemMetrics( SM_CXEDGE ); if ( dwStyle & UDS_ALIGNRIGHT ) rect.right += ( rc.right - rc.left ) - nEdge; else // UDS_ALIGNLEFT rect.left -= ( rc.right - rc.left ) - nEdge; HDC hDC = GetDC( hWnd ); // We must draw the lines onto spin control DC COLORREF clr = GetSysColor( m_nState & dsHoverMask ? COLOR_3DDKSHADOW : COLOR_3DHIGHLIGHT ); if ( !IsWindowEnabled( m_hWnd ) ) clr = GetSysColor( COLOR_3DFACE ); FillSolidRect( hDC, 1, 1, rc.right - rc.left - nEdge - 1, 1, clr ); if ( dwStyle & UDS_ALIGNLEFT ) FillSolidRect( hDC, 1, 1, 1, rc.bottom - rc.top - nEdge - 1, clr ); ReleaseDC( hWnd, hDC ); } } } if ( GetWindowLong( m_hWnd, GWL_STYLE ) & ES_READONLY ) m_nState |= dsDisabled; else m_nState &= ~dsDisabled; CCMControl::DrawControl( hDC, rect ); } LRESULT CCoolControlsManager::CCMEdit::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch ( uMsg ) { case WM_ENABLE: { CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); DrawBorder(); HWND hWnd = GetNextWindow( m_hWnd, GW_HWNDNEXT ); if ( hWnd ) { TCHAR szBuf[MAX_CLASSNAME]; // Retrieve window class name GetClassName( hWnd, szBuf, MAX_CLASSNAME ); if ( lstrcmpi( szBuf, _T( "msctls_updown32" ) ) == 0 && // Up-down is found SendMessage( hWnd, UDM_GETBUDDY, 0, 0L ) == (LONG)m_hWnd ) SendMessage( hWnd, WM_PAINT, 0, 0L ); // Repaint up-down too } } return 0; default: return CCMControl::WindowProc( uMsg, wParam, lParam ); } } ////////////////////////////////////////////////////////////////////////////// // CCMComboBox class void CCoolControlsManager::CCMComboBox::DrawControl( HDC hDC, const RECT& rect ) { // First, draw borders around the control CCMControl::DrawControl( hDC, rect ); // Now, we have to draw borders around the drop-down arrow RECT rc = rect; InflateRect( &rc, -2, -2 ); rc.left = rc.right - GetSystemMetrics( SM_CXHSCROLL ); if ( IsWindowEnabled( m_hWnd ) == TRUE ) { if ( m_nState & dsHoverMask ) Draw3dBorder( hDC, rc, COLOR_3DFACE, COLOR_3DDKSHADOW, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW ); else Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW, COLOR_3DFACE, COLOR_3DFACE ); } else Draw3dBorder( hDC, rc, COLOR_3DFACE, COLOR_3DFACE, COLOR_3DFACE, COLOR_3DFACE ); } BOOL CCoolControlsManager::CCMComboBox::IsFocused() { // Special case for drop-down and simple ComboBoxes // which contain child edit control and focus always // goes to that edit window if ( ( GetWindowLong( m_hWnd, GWL_STYLE ) & 0x03 ) == CBS_DROPDOWN ) { HWND hWnd = GetTopWindow( m_hWnd ); if ( hWnd && hWnd == GetFocus() ) return TRUE; } return CCMControl::IsFocused(); } LRESULT CCoolControlsManager::CCMComboBox::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch ( uMsg ) { // Drop-down ComboBox receives neither WM_SETFOCUS nor WM_KILLFOCUS // Instead, it receives these next two messages case WM_LBUTTONUP: // For kill focus if ( lParam == -1 ) DrawBorder(); break; case WM_COMMAND: if ( HIWORD( wParam ) == EN_SETFOCUS ) DrawBorder(); break; default: return CCMControl::WindowProc( uMsg, wParam, lParam ); } return CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); } ////////////////////////////////////////////////////////////////////////////// // CCMDateTime class void CCoolControlsManager::CCMDateTime::DrawControl( HDC hDC, const RECT& rc ) { if ( GetWindowLong( m_hWnd, GWL_STYLE ) & DTS_UPDOWN ) CCMControl::DrawControl( hDC, rc ); else CCMComboBox::DrawControl( hDC, rc ); } ////////////////////////////////////////////////////////////////////////////// // CCMPushButton class void CCoolControlsManager::CCMPushButton::DrawControl( HDC hDC, const RECT& rc ) { BOOL bDefault = FALSE; // Unfortunately BS_DEFPUSHBUTTON is defined as 0x00000001L, // and BS_OWNERDRAW as 0x0000000BL (see winuser.h) so we cannot // determine the default button for owner-draw controls DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE ) & BS_OWNERDRAW; if ( dwStyle != BS_OWNERDRAW ) { if ( dwStyle == BS_DEFPUSHBUTTON && IsWindowEnabled( m_hWnd ) ) bDefault = TRUE; } int nCheck = SendMessage( m_hWnd, BM_GETCHECK, 0, 0 ); if ( m_nState & dsHoverMask ) { if ( bDefault == TRUE ) { Draw3dBorder( hDC, rc, COLOR_3DDKSHADOW, COLOR_3DDKSHADOW, COLOR_3DHIGHLIGHT, COLOR_3DDKSHADOW, COLOR_3DLIGHT, COLOR_3DSHADOW ); } else { if ( nCheck ) Draw3dBorder( hDC, rc, COLOR_3DDKSHADOW, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW, COLOR_3DLIGHT ); else Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DDKSHADOW, COLOR_3DLIGHT, COLOR_3DSHADOW, COLOR_3DFACE, COLOR_3DFACE ); } } else { if ( bDefault == TRUE ) { Draw3dBorder( hDC, rc, COLOR_3DDKSHADOW, COLOR_3DDKSHADOW, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW, COLOR_3DFACE, COLOR_3DFACE ); } else { if ( nCheck ) Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT, COLOR_3DFACE, COLOR_3DFACE ); else Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW, COLOR_3DFACE, COLOR_3DFACE, COLOR_3DFACE, COLOR_3DFACE ); } } } LRESULT CCoolControlsManager::CCMPushButton::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch ( uMsg ) { // Button messages case BM_SETCHECK: case WM_SETTEXT: CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); DrawBorder(); return 0; default: return CCMControl::WindowProc( uMsg, wParam, lParam ); } } ////////////////////////////////////////////////////////////////////////////// // CCMCheckBox class void CCoolControlsManager::CCMCheckBox::DrawControl( HDC hDC, const RECT& rect ) { DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE ); if ( dwStyle & BS_PUSHLIKE ) { CCMPushButton::DrawControl( hDC, rect ); return; } RECT rc; // Checkmark square size, hard coded here because I couldn't find any // method to obtain this value from the system. // Maybe someone else knows how to do it? If so, please let me know! const int nCheckSize = 13; if ( ( dwStyle & BS_VCENTER ) == BS_VCENTER ) rc.top = rect.top + ( ( rect.bottom - rect.top ) - nCheckSize ) / 2; else if ( dwStyle & BS_TOP ) rc.top = rect.top + 1; else if ( dwStyle & BS_BOTTOM ) rc.top = rect.bottom - nCheckSize - 2; else // Default rc.top = rect.top + ( ( rect.bottom - rect.top ) - nCheckSize ) / 2; if ( dwStyle & BS_LEFTTEXT ) rc.left = rect.right - nCheckSize; else rc.left = rect.left; rc.right = rc.left + nCheckSize; rc.bottom = rc.top + nCheckSize; if ( m_nState & dsHoverMask ) { Draw3dBorder( hDC, rc, COLOR_3DDKSHADOW, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW, COLOR_3DFACE ); } else { if ( IsWindowEnabled( m_hWnd ) == TRUE ) { int nState = SendMessage( m_hWnd, BM_GETCHECK, 0, 0L ); Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT, nState == 2 ? COLOR_3DHIGHLIGHT : COLOR_WINDOW, nState == 2 ? COLOR_3DHIGHLIGHT : COLOR_WINDOW ); } else Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT, COLOR_3DFACE, COLOR_3DFACE ); } } ////////////////////////////////////////////////////////////////////////////// // CCMRadioButton class void CCoolControlsManager::CCMRadioButton::DrawFrame( POINT* ptArr, int nColor, HDC hDC, int xOff, int yOff ) { for ( int i = 0; ; i++ ) { if ( !ptArr[i].x && !ptArr[i].y ) return; SetPixel( hDC, ptArr[i].x + xOff, ptArr[i].y + yOff, GetSysColor( nColor ) ); } } void CCoolControlsManager::CCMRadioButton::DrawControl( HDC hDC, const RECT& rect ) { DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE ); if ( dwStyle & BS_PUSHLIKE ) { CCMPushButton::DrawControl( hDC, rect ); return; } const int nRadioSize = 12; RECT rc; if ( ( dwStyle & BS_VCENTER ) == BS_VCENTER ) rc.top = rect.top + ( ( rect.bottom - rect.top ) - nRadioSize - 1 ) / 2; else if ( dwStyle & BS_TOP ) rc.top = rect.top + 1; else if ( dwStyle & BS_BOTTOM ) rc.top = rect.bottom - nRadioSize - 3; else // Default rc.top = rect.top + ( ( rect.bottom - rect.top ) - nRadioSize - 1 ) / 2; if ( dwStyle & BS_LEFTTEXT ) rc.left = rect.right - nRadioSize; else rc.left = rect.left + 1; rc.right = rc.left + nRadioSize; rc.bottom = rc.top + nRadioSize; POINT pt1[] = { { 1,9 },{ 1,8 }, { 0,7 },{ 0,6 },{ 0,5 },{ 0,4 }, { 1,3 },{ 1,2 }, { 2,1 },{ 3,1 }, { 4,0 },{ 5,0 },{ 6,0 },{ 7,0 }, { 8,1 },{ 9,1 }, { 0,0 } }; POINT pt2[] = { { 2,8 }, { 1,7 },{ 1,6 },{ 1,5 },{ 1,4 }, { 2,3 },{ 2,2 }, { 3,2 }, { 4,1 },{ 5,1 },{ 6,1 },{ 7,1 }, { 8,2 },{ 9,2 }, { 0,0 } }; POINT pt3[] = { { 2,9 },{ 3,9 }, { 4,10 },{ 5,10 },{ 6,10 },{ 7,10 }, { 8,9 },{ 9,9 }, { 9,8 }, { 10,7 },{ 10,6 },{ 10,5 },{ 10,4 }, { 9,3 }, { 0,0 } }; POINT pt4[] = { { 2,10 },{ 3,10 }, { 4,11 },{ 5,11 },{ 6,11 },{ 7,11 }, { 8,10 },{ 9,10 }, { 10,9 },{ 10,8 }, { 11,7 },{ 11,6 },{ 11,5 },{ 11,4 }, { 10,3 },{ 10,2 }, { 0,0 } }; if ( m_nState & dsHoverMask ) { DrawFrame( pt1, COLOR_3DSHADOW, hDC, rc.left, rc.top ); DrawFrame( pt2, COLOR_3DDKSHADOW, hDC, rc.left, rc.top ); DrawFrame( pt3, COLOR_3DFACE, hDC, rc.left, rc.top ); DrawFrame( pt4, COLOR_WINDOW, hDC, rc.left, rc.top ); } else { if ( IsWindowEnabled( m_hWnd ) == TRUE ) { DrawFrame( pt1, COLOR_3DSHADOW, hDC, rc.left, rc.top ); DrawFrame( pt2, COLOR_WINDOW, hDC, rc.left, rc.top ); DrawFrame( pt3, COLOR_3DFACE, hDC, rc.left, rc.top ); DrawFrame( pt4, COLOR_WINDOW, hDC, rc.left, rc.top ); } else { DrawFrame( pt1, COLOR_3DSHADOW, hDC, rc.left, rc.top ); DrawFrame( pt2, COLOR_3DFACE, hDC, rc.left, rc.top ); DrawFrame( pt3, COLOR_3DFACE, hDC, rc.left, rc.top ); DrawFrame( pt4, COLOR_3DHIGHLIGHT, hDC, rc.left, rc.top ); } } } ////////////////////////////////////////////////////////////////////////////// // CCMUpDown class void CCoolControlsManager::CCMUpDown::DrawButton( HDC hDC, const RECT& rc ) { // If associated edit control is disabled // draw the up-down as disabled too BOOL bEnabled = IsWindowEnabled( m_hWnd ); HWND hWnd = (HWND)SendMessage( m_hWnd, UDM_GETBUDDY, 0, 0L ); if ( hWnd ) bEnabled = IsWindowEnabled( hWnd ); if ( bEnabled && m_nState & dsHoverMask ) Draw3dBorder( hDC, rc, COLOR_3DFACE, COLOR_3DDKSHADOW, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW ); else Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW, COLOR_3DFACE, COLOR_3DFACE ); } void CCoolControlsManager::CCMUpDown::DrawControl( HDC hDC, const RECT& rect ) { RECT rc = rect; CCMControl* pCtl = NULL; DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE ); HWND hWnd = (HWND)SendMessage( m_hWnd, UDM_GETBUDDY, 0, 0L ); if ( hWnd && ( dwStyle & UDS_ALIGNRIGHT || dwStyle & UDS_ALIGNLEFT ) ) { if ( dwStyle & UDS_ALIGNLEFT ) rc.left += 2; else // UDS_ALIGNRIGHT rc.right -= 2; rc.top += 2; rc.bottom -= 2; if ( g_ctrlManager.m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) && !( pCtl->GetState() & dsHoverMask ) ) { COLORREF clr1 = GetSysColor( IsWindowEnabled( hWnd ) ? COLOR_3DHIGHLIGHT : COLOR_3DFACE ); COLORREF clr2 = GetSysColor( IsWindowEnabled( hWnd ) ? COLOR_3DLIGHT : COLOR_3DFACE ); FillSolidRect( hDC, rc.left, rc.top - 1, rc.right, 1, clr1 ); FillSolidRect( hDC, rc.left, rc.bottom, rc.right, 1, clr2 ); if ( dwStyle & UDS_ALIGNLEFT ) FillSolidRect( hDC, rc.left - 1, rc.top - 1, 1, rc.bottom, clr1 ); else FillSolidRect( hDC, rc.right, rc.top - 1, 1, rc.bottom, clr2 ); } } RECT r = rc; if ( dwStyle & UDS_HORZ ) { r.right = r.left + ( rc.right - rc.left ) / 2; DrawButton( hDC, r ); r.left = r.right + ( rc.right - rc.left ) % 2; r.right = rc.right; DrawButton( hDC, r ); } else { r.bottom = r.top + ( rc.bottom - rc.top ) / 2; DrawButton( hDC, r ); r.top = r.bottom + ( rc.bottom - rc.top ) % 2; r.bottom = rc.bottom; DrawButton( hDC, r ); } if ( pCtl == NULL ) // Get parent (e.g. for datetime with up-down controls) { hWnd = GetParent( m_hWnd ); g_ctrlManager.m_ctrlMap.Lookup( hWnd, (void*&)pCtl ); } if ( pCtl && IsWindowEnabled( hWnd ) ) // Redraw parent or buddy if neccesary { if ( m_nState & dsHoverMask ) pCtl->SetState( 0, dsHover ); else pCtl->SetState( dsHover, 0 ); } } ////////////////////////////////////////////////////////////////////////////// // CCMEditCombo class void CCoolControlsManager::CCMEditCombo::PrepareDraw( HDC& hDC, RECT& rect ) { GetWindowRect( m_hWnd, &rect ); InflateRect( &rect, 3, 3 ); OffsetRect( &rect, -rect.left, -rect.top ); // Draw onto that DC that is most suitable for given class hDC = GetWindowDC( GetParent( m_hWnd ) ); } ////////////////////////////////////////////////////////////////////////////// // CCMScrollBar class void CCoolControlsManager::CCMScrollBar::DrawControl( HDC hDC, const RECT& rc ) { DrawScrollBar( hDC, rc, ( GetWindowLong( m_hWnd, GWL_STYLE ) & SBS_VERT ) ? SB_VERT : SB_HORZ, TRUE ); } LRESULT CCoolControlsManager::CCMScrollBar::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch ( uMsg ) { // Scrollbar messages case SBM_SETPOS: if ( !lParam ) // redraw flag break; case SBM_SETSCROLLINFO: if ( !wParam ) // redraw flag break; case SBM_SETRANGEREDRAW: CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); DrawBorder(); return 0; default: return CCMControl::WindowProc( uMsg, wParam, lParam ); } return CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); } ////////////////////////////////////////////////////////////////////////////// // CCMHeaderCtrl class void CCoolControlsManager::CCMHeaderCtrl::DrawButton( HDC hDC, const RECT& rc, int nState ) { if ( nState & dsHoverMask ) Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DDKSHADOW, COLOR_3DLIGHT, COLOR_3DSHADOW ); else Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW, COLOR_3DFACE, COLOR_3DFACE ); } void CCoolControlsManager::CCMHeaderCtrl::DrawControl( HDC hDC, const RECT& /*rc*/ ) { int nOldItem = m_nOldItem; m_nOldItem = -1; RECT rc; POINT point; GetCursorPos( &point ); // This code fails if we will have standalone header control but such cases are rare... HWND hWnd = GetParent( m_hWnd ); GetClientRect( GetParent( m_hWnd ), &rc ); ScreenToClient( GetParent( m_hWnd ), &point ); // Test if mouse pointer is within the client area of the list control BOOL bInView = PtInRect( &rc, point ); GetClientRect( m_hWnd, &rc ); rc.right = 0; GetCursorPos( &point ); ScreenToClient( m_hWnd, &point ); hDC = GetDC( m_hWnd ); int nState; int nCount = SendMessage( m_hWnd, HDM_GETITEMCOUNT, 0, 0L ); for ( int i = 0; i < nCount; i++ ) { #if (_WIN32_IE >= 0x0300) HDITEM hi; hi.mask = HDI_ORDER; SendMessage( m_hWnd, HDM_GETITEM, i, (LPARAM)&hi ); SendMessage( m_hWnd, HDM_GETITEMRECT, hi.iOrder, (LPARAM)&rc ); #else SendMessage( m_hWnd, HDM_GETITEMRECT, i, (LPARAM)&rc ); #endif nState = 0; if ( bInView & PtInRect( &rc, point ) ) { nState = dsHover; #if (_WIN32_IE >= 0x0300) m_nOldItem = hi.iOrder; #else m_nOldItem = i; #endif } DrawButton( hDC, rc, nState ); } int l = rc.right; GetClientRect( m_hWnd, &rc ); rc.left = l; DrawButton( hDC, rc, 0 ); // If header is a child of ListView, redraw the list so // it will indicate proper state CCMControl* pCtl; if ( g_ctrlManager.m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) ) { if ( m_nOldItem >= 0 ) pCtl->SetState( 0, dsHover ); else if ( nOldItem >= 0 ) pCtl->SetState( dsHover, 0 ); } ReleaseDC( m_hWnd, hDC ); } BOOL CCoolControlsManager::CCMHeaderCtrl::NeedRedraw( const POINT& point ) { RECT rc; GetClientRect( m_hWnd, &rc ); rc.right = 0; POINT pt = point; ScreenToClient( m_hWnd, &pt ); int nItem = -1; int nCount = SendMessage( m_hWnd, HDM_GETITEMCOUNT, 0, 0L ); for ( int i = 0; i < nCount; i++ ) { HDITEM hi; hi.mask = HDI_WIDTH; SendMessage( m_hWnd, HDM_GETITEM, i, (LPARAM)&hi ); rc.left = rc.right; rc.right = rc.left + hi.cxy; if ( PtInRect( &rc, pt ) ) { nItem = i; break; } } if ( m_hWnd != m_hWndOld || ( m_hWnd == m_hWndOld && m_nOldItem != nItem ) ) return TRUE; return FALSE; } ////////////////////////////////////////////////////////////////////////////// // CCMTrackbar class void CCoolControlsManager::CCMTrackbar::DrawThumb( HDC hDC, const RECT& rc ) { DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE ); if ( dwStyle & TBS_BOTH ) { FillSolidRect( hDC, rc, GetSysColor( COLOR_3DFACE ) ); if ( m_nState & dsHoverMask ) Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DDKSHADOW, COLOR_3DLIGHT, COLOR_3DSHADOW ); else Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW, COLOR_3DFACE, COLOR_3DFACE ); return; } HPEN penHighlight = CreatePen( PS_SOLID, 1, GetSysColor( COLOR_3DHIGHLIGHT ) ); HPEN penLight = CreatePen( PS_SOLID, 1, GetSysColor( m_nState & dsHoverMask ? COLOR_3DLIGHT : COLOR_3DFACE ) ); HPEN penDkShadow = CreatePen( PS_SOLID, 1, GetSysColor( m_nState & dsHoverMask ? COLOR_3DDKSHADOW : COLOR_3DSHADOW ) ); HPEN penShadow = CreatePen( PS_SOLID, 1, GetSysColor( m_nState & dsHoverMask ? COLOR_3DSHADOW : COLOR_3DFACE ) ); int n; if ( dwStyle & TBS_VERT ) { if ( dwStyle & TBS_LEFT ) { n = ( rc.bottom - rc.top ) / 2 + 1; FillSolidRect( hDC, rc, GetSysColor( COLOR_3DFACE ) ); HPEN hOldPen = (HPEN)SelectObject( hDC, penHighlight ); MoveToEx( hDC, rc.right - 2, rc.top, NULL ); LineTo( hDC, rc.left + n - 1, rc.top ); LineTo( hDC, rc.left, rc.top + n - 1 ); SelectObject( hDC, penDkShadow ); LineTo( hDC, rc.left + n - 1, rc.bottom - 1 ); LineTo( hDC, rc.right - 1, rc.bottom - 1 ); LineTo( hDC, rc.right - 1, rc.top - 1 ); SelectObject( hDC, penLight ); MoveToEx( hDC, rc.right - 3, rc.top + 1, NULL ); LineTo( hDC, rc.left + n - 1, rc.top + 1 ); LineTo( hDC, rc.left + 1, rc.top + n - 1 ); SelectObject( hDC, penShadow ); LineTo( hDC, rc.left + n - 1, rc.bottom - 2 ); LineTo( hDC, rc.right - 2, rc.bottom - 2 ); LineTo( hDC, rc.right - 2, rc.top ); SelectObject( hDC, hOldPen ); } else // TBS_RIGHT { n = ( rc.bottom - rc.top ) / 2 + 1; FillSolidRect( hDC, rc, GetSysColor( COLOR_3DFACE ) ); HPEN hOldPen = (HPEN)SelectObject( hDC, penHighlight ); MoveToEx( hDC, rc.left, rc.bottom - 2, NULL ); LineTo( hDC, rc.left, rc.top ); LineTo( hDC, rc.right - n, rc.top ); LineTo( hDC, rc.right - 1, rc.top + n - 1 ); SelectObject( hDC, penDkShadow ); MoveToEx( hDC, rc.left, rc.bottom - 1, NULL ); LineTo( hDC, rc.right - n, rc.bottom - 1 ); LineTo( hDC, rc.right, rc.top + n - 2 ); SelectObject( hDC, penLight ); MoveToEx( hDC, rc.left + 1, rc.bottom - 3, NULL ); LineTo( hDC, rc.left + 1, rc.top + 1 ); LineTo( hDC, rc.right - n, rc.top + 1 ); LineTo( hDC, rc.right - 2, rc.top + n - 1 ); SelectObject( hDC, penShadow ); MoveToEx( hDC, rc.left + 1, rc.bottom - 2, NULL ); LineTo( hDC, rc.right - n, rc.bottom - 2 ); LineTo( hDC, rc.right - 1, rc.top + n - 2 ); SelectObject( hDC, hOldPen ); } } else { if ( dwStyle & TBS_TOP ) { n = ( rc.right - rc.left ) / 2 + 1; FillSolidRect( hDC, rc, GetSysColor( COLOR_3DFACE ) ); HPEN hOldPen = (HPEN)SelectObject( hDC, penHighlight ); MoveToEx( hDC, rc.left + n - 2, rc.top + 1, NULL ); LineTo( hDC, rc.left, rc.top + n - 1 ); LineTo( hDC, rc.left, rc.bottom - 1 ); SelectObject( hDC, penDkShadow ); LineTo( hDC, rc.right - 1, rc.bottom - 1 ); LineTo( hDC, rc.right - 1, rc.top + n - 1 ); LineTo( hDC, rc.left + n - 2, rc.top - 1 ); SelectObject( hDC, penLight ); MoveToEx( hDC, rc.left + n - 2, rc.top + 2, NULL ); LineTo( hDC, rc.left + 1, rc.top + n - 1 ); LineTo( hDC, rc.left + 1, rc.bottom - 2 ); SelectObject( hDC, penShadow ); LineTo( hDC, rc.right - 2, rc.bottom - 2 ); LineTo( hDC, rc.right - 2, rc.top + n - 1 ); LineTo( hDC, rc.left + n - 2, rc.top ); SelectObject( hDC, hOldPen ); } else // TBS_BOTTOM { n = ( rc.right - rc.left ) / 2 + 1; FillSolidRect( hDC, rc, GetSysColor( COLOR_3DFACE ) ); HPEN hOldPen = (HPEN)SelectObject( hDC, penHighlight ); MoveToEx( hDC, rc.left + n - 2, rc.bottom - 2, NULL ); LineTo( hDC, rc.left, rc.bottom - n ); LineTo( hDC, rc.left, rc.top ); LineTo( hDC, rc.right - 1, rc.top ); SelectObject( hDC, penDkShadow ); LineTo( hDC, rc.right - 1, rc.bottom - n ); LineTo( hDC, rc.left + n - 2, rc.bottom ); SelectObject( hDC, penLight ); MoveToEx( hDC, rc.left + n - 2, rc.bottom - 3, NULL ); LineTo( hDC, rc.left + 1, rc.bottom - n ); LineTo( hDC, rc.left + 1, rc.top + 1 ); LineTo( hDC, rc.right - 2, rc.top + 1 ); SelectObject( hDC, penShadow ); LineTo( hDC, rc.right - 2, rc.bottom - n ); LineTo( hDC, rc.left + n - 2, rc.bottom - 1 ); SelectObject( hDC, hOldPen ); } } DeleteObject( penHighlight ); DeleteObject( penLight ); DeleteObject( penDkShadow ); DeleteObject( penShadow ); } void CCoolControlsManager::CCMTrackbar::DrawControl( HDC hDC, const RECT& /*rect*/ ) { hDC = GetDC( m_hWnd ); DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE ); RECT rc; SendMessage( m_hWnd, TBM_GETCHANNELRECT, 0, (LPARAM)&rc ); // BUG!: Windows incorrectly calculates the channel rectangle for // sliders with TBS_VERT style, so we have to calculate the rectangle // in different manner. This bug appears on all Windows platforms! if ( dwStyle & TBS_VERT ) { int w = ( rc.right - rc.left ); int h = ( rc.bottom - rc.top ); rc.top = rc.left; rc.bottom = rc.left + w; RECT r; SendMessage( m_hWnd, TBM_GETTHUMBRECT, 0, (LPARAM)&r ); rc.left = r.left + ( ( r.right - r.left ) / 2 + 1 ) - h / 2; if ( dwStyle & TBS_LEFT ) ; else if ( dwStyle & TBS_BOTH ) rc.left -= 1; else rc.left -= 2; rc.right = rc.left + h; } // Draw the channel rect if ( m_nState & dsHoverMask ) Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT, COLOR_3DDKSHADOW, COLOR_3DLIGHT ); else Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT, COLOR_3DFACE, COLOR_3DFACE ); // Draw the slider thumb if ( !( dwStyle & TBS_NOTHUMB ) ) { SetRectEmpty( &rc ); SendMessage( m_hWnd, TBM_GETTHUMBRECT, 0, (LPARAM)&rc ); DrawThumb( hDC, rc ); } ReleaseDC( m_hWnd, hDC ); } ////////////////////////////////////////////////////////////////////////////// // CCMToolbar class void CCoolControlsManager::CCMToolbar::DrawButton( HDC hDC, const RECT& rc, int nState ) { if ( nState & bsChecked ) { if ( nState & bsHover ) Draw3dBorder( hDC, rc, COLOR_3DDKSHADOW, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW, COLOR_3DSHADOW ); else Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT, COLOR_3DFACE, COLOR_3DFACE ); } else { if ( nState & bsHover ) Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DDKSHADOW, COLOR_3DLIGHT, COLOR_3DSHADOW ); else Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW, COLOR_3DFACE, COLOR_3DFACE ); } } void CCoolControlsManager::CCMToolbar::DrawControl( HDC hDC, const RECT& /*rc*/ ) { if ( GetWindowLong( m_hWnd, GWL_STYLE ) & TBSTYLE_FLAT ) // Skip flat toolbars return; int nCount = SendMessage( m_hWnd, TB_BUTTONCOUNT, 0, 0L ); hDC = GetDC( m_hWnd ); // We will draw toolbar buttons on the client DC POINT point; GetCursorPos( &point ); ScreenToClient( m_hWnd, &point ); m_nOldItem = -1; int nState = 0; for ( int i = 0; i < nCount; i++ ) { RECT rc; TBBUTTON ti; SendMessage( m_hWnd, TB_GETBUTTON, i, (LPARAM)&ti ); SendMessage( m_hWnd, TB_GETITEMRECT, i, (LPARAM)&rc ); if ( !( ti.fsStyle & TBSTYLE_SEP ) ) { nState = ( ti.fsState & TBSTATE_CHECKED ) ? bsChecked : bsNormal; if ( PtInRect( &rc, point ) == TRUE ) { if ( ti.fsState & TBSTATE_ENABLED ) nState |= bsHover; m_nOldItem = i; } DrawButton( hDC, rc, nState ); } } ReleaseDC( m_hWnd, hDC ); } BOOL CCoolControlsManager::CCMToolbar::NeedRedraw( const POINT& point ) { int nCount = SendMessage( m_hWnd, TB_BUTTONCOUNT, 0, 0L ); POINT pt = point; ScreenToClient( m_hWnd, &pt ); int nItem = -1; for ( int i = 0; i < nCount; i++ ) { TBBUTTON ti; SendMessage( m_hWnd, TB_GETBUTTON, i, (LPARAM)&ti ); if ( !( ti.fsStyle & TBSTYLE_SEP ) ) { RECT rc; SendMessage( m_hWnd, TB_GETITEMRECT, i, (LPARAM)&rc ); if ( PtInRect( &rc, pt ) ) { nItem = i; break; } } } if ( m_hWnd != m_hWndOld || ( m_hWnd == m_hWndOld && m_nOldItem != nItem ) ) return TRUE; return FALSE; } LRESULT CCoolControlsManager::CCMToolbar::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch ( uMsg ) { case WM_PAINT: case WM_NCPAINT: m_nOldItem = -1; // Redraw the whole toolbar unconditionally default: return CCMControl::WindowProc( uMsg, wParam, lParam ); } } ////////////////////////////////////////////////////////////////////////////// // CCMTabControl class void CCoolControlsManager::CCMTabControl::DrawTab( HDC hDC, const RECT& rect, int nItem, int nState ) { RECT rc = rect; int nCurSel = SendMessage( m_hWnd, TCM_GETCURSEL, 0, 0L ); if ( nCurSel == -1 ) nCurSel = -2; switch ( GetOrientation() ) { case tabLeft: if ( nState & bsChecked ) { rc.top -= 2; rc.bottom += 2; rc.left -= 2; rc.right += 1; } if ( nState & bsHover ) { if ( nCurSel != nItem - 1 ) { FillSolidRect( hDC, rc.left+2, rc.top, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DHIGHLIGHT ) ); FillSolidRect( hDC, rc.left+2, rc.top+1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DLIGHT ) ); SetPixel( hDC, rc.left+1, rc.top+1, GetSysColor( COLOR_3DHIGHLIGHT ) ); } FillSolidRect( hDC, rc.left, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DHIGHLIGHT ) ); FillSolidRect( hDC, rc.left+1, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DLIGHT ) ); if ( nCurSel != nItem + 1 ) { FillSolidRect( hDC, rc.left+2, rc.bottom-1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DDKSHADOW ) ); FillSolidRect( hDC, rc.left+2, rc.bottom-2, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DSHADOW ) ); SetPixel( hDC, rc.left+1, rc.bottom-2, GetSysColor( COLOR_3DDKSHADOW ) ); } } else { if ( nCurSel != nItem - 1 ) { FillSolidRect( hDC, rc.left+2, rc.top, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DHIGHLIGHT ) ); FillSolidRect( hDC, rc.left+2, rc.top+1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DFACE ) ); SetPixel( hDC, rc.left+1, rc.top+1, GetSysColor( COLOR_3DHIGHLIGHT ) ); } FillSolidRect( hDC, rc.left, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DHIGHLIGHT ) ); FillSolidRect( hDC, rc.left+1, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DFACE ) ); if ( nCurSel != nItem + 1 ) { FillSolidRect( hDC, rc.left+2, rc.bottom-1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DSHADOW ) ); FillSolidRect( hDC, rc.left+2, rc.bottom-2, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DFACE ) ); SetPixel( hDC, rc.left+1, rc.bottom-2, GetSysColor( COLOR_3DSHADOW ) ); } } break; case tabTop: if ( nState & bsChecked ) { rc.top -= 2; rc.bottom += 1; rc.left -= 2; rc.right += 2; } if ( nState & bsHover ) { if ( nCurSel != nItem - 1 ) { FillSolidRect( hDC, rc.left, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DHIGHLIGHT ) ); FillSolidRect( hDC, rc.left+1, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DLIGHT ) ); SetPixel( hDC, rc.left+1, rc.top+1, GetSysColor( COLOR_3DHIGHLIGHT ) ); } FillSolidRect( hDC, rc.left+2, rc.top, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DHIGHLIGHT ) ); FillSolidRect( hDC, rc.left+2, rc.top+1, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DLIGHT ) ); if ( nCurSel != nItem + 1 ) { FillSolidRect( hDC, rc.right-1, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DDKSHADOW ) ); FillSolidRect( hDC, rc.right-2, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DSHADOW ) ); SetPixel( hDC, rc.right-2, rc.top+1, GetSysColor( COLOR_3DDKSHADOW ) ); } } else { if ( nCurSel != nItem - 1 ) { FillSolidRect( hDC, rc.left, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DHIGHLIGHT ) ); FillSolidRect( hDC, rc.left+1, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DFACE ) ); SetPixel( hDC, rc.left+1, rc.top+1, GetSysColor( COLOR_3DHIGHLIGHT ) ); } FillSolidRect( hDC, rc.left+2, rc.top, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DHIGHLIGHT ) ); FillSolidRect( hDC, rc.left+2, rc.top+1, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DFACE ) ); if ( nCurSel != nItem + 1 ) { FillSolidRect( hDC, rc.right-1, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DSHADOW ) ); FillSolidRect( hDC, rc.right-2, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DFACE ) ); SetPixel( hDC, rc.right-2, rc.top+1, GetSysColor( COLOR_3DSHADOW ) ); } } break; case tabRight: if ( nState & bsChecked ) { rc.top -= 2; rc.bottom += 2; rc.right += 2; rc.left -= 1; } if ( nState & bsHover ) { if ( nCurSel != nItem - 1 ) { FillSolidRect( hDC, rc.left, rc.top, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DHIGHLIGHT ) ); FillSolidRect( hDC, rc.left, rc.top+1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DLIGHT ) ); SetPixel( hDC, rc.right-2, rc.top+1, GetSysColor( COLOR_3DHIGHLIGHT ) ); } FillSolidRect( hDC, rc.right-1, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DDKSHADOW ) ); FillSolidRect( hDC, rc.right-2, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DSHADOW ) ); if ( nCurSel != nItem + 1 ) { FillSolidRect( hDC, rc.left, rc.bottom-2, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DSHADOW ) ); FillSolidRect( hDC, rc.left, rc.bottom-1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DDKSHADOW ) ); SetPixel( hDC, rc.right-2, rc.bottom-2, GetSysColor( COLOR_3DDKSHADOW ) ); } } else { if ( nCurSel != nItem - 1 ) { FillSolidRect( hDC, rc.left, rc.top, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DHIGHLIGHT ) ); FillSolidRect( hDC, rc.left, rc.top+1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DFACE ) ); SetPixel( hDC, rc.right-2, rc.top+1, GetSysColor( COLOR_3DHIGHLIGHT ) ); } FillSolidRect( hDC, rc.right-1, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DSHADOW ) ); FillSolidRect( hDC, rc.right-2, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DFACE ) ); if ( nCurSel != nItem + 1 ) { FillSolidRect( hDC, rc.left, rc.bottom-1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DSHADOW ) ); FillSolidRect( hDC, rc.left, rc.bottom-2, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DFACE ) ); SetPixel( hDC, rc.right-2, rc.bottom-2, GetSysColor( COLOR_3DSHADOW ) ); } } break; case tabBottom: if ( nState & bsChecked ) { rc.bottom += 2; rc.left -= 2; rc.right += 2; rc.top -=1; } if ( nState & bsHover ) { if ( nCurSel != nItem - 1 ) { FillSolidRect( hDC, rc.left, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DHIGHLIGHT ) ); FillSolidRect( hDC, rc.left+1, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DLIGHT ) ); SetPixel( hDC, rc.left+1, rc.bottom-2, GetSysColor( COLOR_3DHIGHLIGHT ) ); } FillSolidRect( hDC, rc.left+2, rc.bottom-1, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DDKSHADOW ) ); FillSolidRect( hDC, rc.left+2, rc.bottom-2, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DSHADOW ) ); if ( nCurSel != nItem + 1 ) { FillSolidRect( hDC, rc.right-1, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DDKSHADOW ) ); FillSolidRect( hDC, rc.right-2, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DSHADOW ) ); SetPixel( hDC, rc.right-2, rc.bottom-2, GetSysColor( COLOR_3DDKSHADOW ) ); } } else { if ( nCurSel != nItem - 1 ) { FillSolidRect( hDC, rc.left, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DHIGHLIGHT ) ); FillSolidRect( hDC, rc.left+1, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DFACE ) ); SetPixel( hDC, rc.left+1, rc.bottom-2, GetSysColor( COLOR_3DHIGHLIGHT ) ); } FillSolidRect( hDC, rc.left+2, rc.bottom-1, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DSHADOW ) ); FillSolidRect( hDC, rc.left+2, rc.bottom-2, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DFACE ) ); if ( nCurSel != nItem + 1 ) { FillSolidRect( hDC, rc.right-1, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DSHADOW ) ); FillSolidRect( hDC, rc.right-2, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DFACE ) ); SetPixel( hDC, rc.right-2, rc.bottom-2, GetSysColor( COLOR_3DSHADOW ) ); } } break; } } CCoolControlsManager::CCMTabControl::OrientationsEnum CCoolControlsManager::CCMTabControl::GetOrientation() const { DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE ); if ( dwStyle & TCS_BOTTOM ) { if ( dwStyle & TCS_VERTICAL ) return tabRight; else return tabBottom; } else { if ( dwStyle & TCS_VERTICAL ) return tabLeft; else return tabTop; } } void CCoolControlsManager::CCMTabControl::DrawControl( HDC hDC, const RECT& rect ) { DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE ); if ( dwStyle & TCS_BUTTONS ) // Skip button-like tab controls return; hDC = GetDC( m_hWnd ); // We will draw on the client DC RECT rc = rect; SendMessage( m_hWnd, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc ); InflateRect( &rc, 4, 4 ); RECT rcSel; int nCurSel = SendMessage( m_hWnd, TCM_GETCURSEL, 0, 0L ); SendMessage( m_hWnd, TCM_GETITEMRECT, nCurSel, (LPARAM)&rcSel ); switch ( GetOrientation() ) { case tabLeft: rc.left += 2; FillSolidRect( hDC, rc.left, rc.bottom, rc.right-rc.left, -1, GetSysColor( COLOR_3DSHADOW ) ); FillSolidRect( hDC, rc.right, rc.top, -1, rc.bottom-rc.top, GetSysColor( COLOR_3DSHADOW ) ); break; case tabTop: rc.top += 2; FillSolidRect( hDC, rc.left, rc.bottom, rc.right-rc.left, -1, GetSysColor( COLOR_3DSHADOW ) ); FillSolidRect( hDC, rc.right, rc.top, -1, rc.bottom-rc.top, GetSysColor( COLOR_3DSHADOW ) ); break; case tabRight: rc.right -= 2; FillSolidRect( hDC, rc.left, rc.bottom, rc.right-rc.left, -1, GetSysColor( COLOR_3DSHADOW ) ); FillSolidRect( hDC, rc.right, rc.top, -1, rcSel.top-rc.top, GetSysColor( COLOR_3DSHADOW ) ); FillSolidRect( hDC, rc.right, rcSel.bottom, -1, rc.bottom-rcSel.bottom, GetSysColor( COLOR_3DSHADOW ) ); break; case tabBottom: rc.bottom -= 2; FillSolidRect( hDC, rc.left, rc.bottom, rcSel.left-rc.left, -1, GetSysColor( COLOR_3DSHADOW ) ); FillSolidRect( hDC, rcSel.right, rc.bottom, rc.right-rcSel.right, -1, GetSysColor( COLOR_3DSHADOW ) ); FillSolidRect( hDC, rc.right, rc.top, -1, rc.bottom-rc.top, GetSysColor( COLOR_3DSHADOW ) ); break; } Draw3dRect( hDC, rc.left+1, rc.top+1, rc.right-rc.left-2, rc.bottom-rc.top-2, GetSysColor( COLOR_3DFACE ), GetSysColor( COLOR_3DFACE ) ); m_nOldItem = -1; int nState = 0; POINT point; GetCursorPos( &point ); ScreenToClient( m_hWnd, &point ); int nCount = SendMessage( m_hWnd, TCM_GETITEMCOUNT, 0, 0L ); for ( int i = 0; i < nCount; i++ ) { SendMessage( m_hWnd, TCM_GETITEMRECT, i, (LPARAM)&rc ); nState = bsNormal; if ( nCurSel != i ) { if ( PtInRect( &rc, point ) == TRUE ) { nState |= bsHover; m_nOldItem = i; } DrawTab( hDC, rc, i, nState ); } } nState = bsChecked; if ( PtInRect( &rcSel, point ) == TRUE ) { nState |= bsHover; m_nOldItem = nCurSel; } DrawTab( hDC, rcSel, nCurSel, nState ); if ( nCurSel != 0 ) switch ( GetOrientation() ) { case tabTop: FillSolidRect( hDC, rect.left, rect.top, 2, rcSel.bottom-rcSel.top+2, GetSysColor( COLOR_3DFACE ) ); break; case tabBottom: FillSolidRect( hDC, rect.left, rect.bottom, 2, -rcSel.bottom+rcSel.top-2, GetSysColor( COLOR_3DFACE ) ); break; } ReleaseDC( m_hWnd, hDC ); } BOOL CCoolControlsManager::CCMTabControl::NeedRedraw( const POINT& point ) { int nCount = SendMessage( m_hWnd, TCM_GETITEMCOUNT, 0, 0L ); TCHITTESTINFO thti; thti.pt = point; ScreenToClient( m_hWnd, &thti.pt ); int nItem = SendMessage( m_hWnd, TCM_HITTEST, 0, (LPARAM)&thti ); if ( m_hWnd != m_hWndOld || ( m_hWnd == m_hWndOld && m_nOldItem != nItem ) ) return TRUE; return FALSE; } LRESULT CCoolControlsManager::CCMTabControl::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch ( uMsg ) { case WM_PAINT: case WM_NCPAINT: m_nOldItem = -1; // Redraw the whole control unconditionally break; } return CCMControl::WindowProc( uMsg, wParam, lParam ); } ////////////////////////////////////////////////////////////////////////////// // CCMIPAddress class BOOL CCoolControlsManager::CCMIPAddress::IsFocused() { HWND hWnd = GetTopWindow( m_hWnd ); while ( hWnd ) { if ( hWnd == GetFocus() ) return TRUE; hWnd = GetNextWindow( hWnd, GW_HWNDNEXT ); } return FALSE; } LRESULT CCoolControlsManager::CCMIPAddress::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch ( uMsg ) { case WM_COMMAND: if ( HIWORD( wParam ) == EN_SETFOCUS || HIWORD( wParam ) == EN_KILLFOCUS ) DrawBorder(); break; default: return CCMControl::WindowProc( uMsg, wParam, lParam ); } return CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); } ////////////////////////////////////////////////////////////////////////////// // CCMDialog class LRESULT CCoolControlsManager::CCMDialog::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch ( uMsg ) { case WM_PARENTNOTIFY: if ( LOWORD( wParam ) == WM_CREATE ) // Add dynamically created controls to the map g_ctrlManager.AddControl( (HWND)lParam ); break; case WM_NCDESTROY: // Unsubclass window and remove it from the map CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); g_ctrlManager.RemoveDialog( m_hWnd ); return 0; } return CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); } /////////////////////////////////////////////////////////////////////////////////// // Helper functions for drawing 3D frames (borrowed from CDC class) void CCoolControlsManager::CCMControl::FillSolidRect( HDC hDC, int x, int y, int cx, int cy, COLORREF clr ) { SetBkColor( hDC, clr ); RECT rect; SetRect( &rect, x, y, x + cx, y + cy ); ExtTextOut( hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL ); } void CCoolControlsManager::CCMControl::FillSolidRect( HDC hDC, const RECT& rect, COLORREF clr ) { SetBkColor( hDC, clr ); ExtTextOut( hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL ); } void CCoolControlsManager::CCMControl::Draw3dRect( HDC hDC, int x, int y, int cx, int cy, COLORREF clrTopLeft, COLORREF clrBottomRight ) { FillSolidRect( hDC, x, y, cx - 1, 1, clrTopLeft ); FillSolidRect( hDC, x, y, 1, cy - 1, clrTopLeft ); FillSolidRect( hDC, x + cx, y, -1, cy, clrBottomRight ); FillSolidRect( hDC, x, y + cy, cx, -1, clrBottomRight ); } void CCoolControlsManager::CCMControl::Draw3dRect( HDC hDC, const RECT& rect, COLORREF clrTopLeft, COLORREF clrBottomRight ) { Draw3dRect( hDC, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, clrTopLeft, clrBottomRight ); } void CCoolControlsManager::CCMControl::Draw3dBorder( HDC hDC, const RECT& rc, int nColor1, int nColor2, int nColor3, int nColor4 ) { Draw3dRect( hDC, rc, GetSysColor( nColor1 ), GetSysColor( nColor2 ) ); Draw3dRect( hDC, rc.left + 1, rc.top + 1, rc.right - rc.left - 2, rc.bottom - rc.top - 2, GetSysColor( nColor3 ), GetSysColor( nColor4 ) ); } void CCoolControlsManager::CCMControl::Draw3dBorder( HDC hDC, const RECT& rc, int nColor1, int nColor2, int nColor3, int nColor4, int nColor5, int nColor6 ) { Draw3dRect( hDC, rc, GetSysColor( nColor1 ), GetSysColor( nColor2 ) ); Draw3dRect( hDC, rc.left + 1, rc.top + 1, rc.right - rc.left - 2, rc.bottom - rc.top - 2, GetSysColor( nColor3 ), GetSysColor( nColor4 ) ); Draw3dRect( hDC, rc.left + 2, rc.top + 2, rc.right - rc.left - 4, rc.bottom - rc.top - 4, GetSysColor( nColor5 ), GetSysColor( nColor6 ) ); }